package services

import (
	"context"
	"errors"
	"ginchat/internal/globals/databases"
	"ginchat/internal/pb"
	"ginchat/utils/jwt"
	"github.com/spf13/viper"
	"time"
)

type TokenService struct {
	pb.UnimplementedTokenServiceServer
}

const TokenPrefix = "GIN-CHAT-TOKEN_"

func (t *TokenService) VerifyToken(ctx context.Context, request *pb.TokenRequest) (*pb.VerifyTokenResponse, error) {
	token := request.GetToken()
	claim, err := jwt.VerifyToken(token, []byte(viper.GetString("system.SecretKey")))
	if err != nil {
		return nil, err
	}

	redisManager := databases.GetRedisClient()
	result, err := redisManager.HGetAll(ctx, TokenPrefix+claim.UserID).Result()
	if err != nil || result["token"] != token {
		return nil, errors.New("the token has expired")
	}

	err = redisManager.Expire(
		ctx,
		TokenPrefix+claim.UserID,
		time.Second*time.Duration(viper.GetInt("system.TokenExpireTime")),
	).Err()
	if err != nil {
		return nil, errors.New("refresh token failed")
	}
	return &pb.VerifyTokenResponse{
		UserId: claim.UserID,
	}, nil
}

func (t *TokenService) FreeToken(ctx context.Context, request *pb.TokenRequest) (*pb.FreeTokenResponse, error) {
	token := request.GetToken()
	claims, err := jwt.VerifyToken(token, []byte(viper.GetString("system.SecretKey")))
	if err != nil {
		return nil, err
	}

	rds := databases.GetRedisClient()
	err = rds.Del(ctx, TokenPrefix+claims.UserID).Err()
	if err != nil {
		return nil, errors.New("failed to free token")
	}
	return &pb.FreeTokenResponse{}, nil
}

func (t *TokenService) GenerateToken(ctx context.Context, req *pb.GenerateTokenRequest) (*pb.GenerateTokenResponse, error) {
	claim := jwt.JWTClaims{
		UserID: req.GetUserId(),
	}
	token, err := claim.MakeToken(
		viper.GetInt("system.TokenExpireTime"),
		[]byte(viper.GetString("system.SecretKey")),
	)
	if err != nil {
		return nil, err
	}

	return &pb.GenerateTokenResponse{
		Token: token,
	}, nil
}
